import {
  getExamComments,
  getSingleExamComments,
  getMoreExamComments,
  saveExamComment
} from '@/api/exam.js'
export default {
  namespaced: true,
  state: {
    // 考试状态 1练习模式 2考试模式 //初始化试题的时候，存储一份当前试题信息，静态
    examInitModel: 1,
    // 试卷id
    examId: 0,
    // 已做题数
    examDoneNum: 0,
    // 试卷题目信息
    examQuestion: {},
    // 当前问题
    currentQuestion: {},
    //考试模式 : 1- 练习模式  2 - 考试模式 3 - 背题模式 ，可以动态改变
    examModel: 1,
    //将试题的评论存入store
    allComments: {},
    //将所有评论的点赞objectid，存入store
    allLikes: [],
    //讨论类型：1 - 精彩讨论 2 - 当前讨论
    commentStick: 1,
    //回复信息
    replyInfo: null,
    //查看所有回复信息，列表
    replyAllInfo: null,
    //是否正在请求更多评论
    isQuestMoreComments: false,
    //是否禁用评论/点赞按钮
    isDisabledReplyBtn: false,
    // 是否交卷
    isSubmitedPaper: false,
    // 记录当前组合题中小题的题号
    subQuestionIndex: '0',
    // 练习模式下的做题时长 s
    timeConsuming: 0
  },
  mutations: {
    SET_TIME_CONSUMING(state, data) {
      storage.set(`timeConsuming_` + state.examId, data)
      state.timeConsuming = data
    },
    SET_EXAM_INIT_MODEL(state, data) {
      state.examInitModel = data
    },
    SET_EXAM_MODEL(state, data) {
      state.examModel = data
    },
    SET_EXAM_ID(state, data) {
      state.examId = data
    },
    SET_CURRENT_QUESTION(state, data) {
      state.currentQuestion = data
    },
    SET_IS_SUBMITED_PAPER(state, data) {
      state.isSubmitedPaper = data
    },
    SET_SUB_QUESTION_INDEX(state, data) {
      state.subQuestionIndex = data
    },
    // 存储试题
    setExamQuestion(state, data) {
      state.examQuestion = data
      storage.set(
        'question_' + state.examId,
        JSON.stringify(state.examQuestion)
      )
    },
    // 更新试题的questionsList
    updateQuestionsList(state, data) {
      state.examQuestion.questionsList = data || []
      this.commit('exam/setExamQuestion', state.examQuestion)
    },

    // 更新试题
    updateExamQuestion(state, data) {
      let oldExamQuestion = state.examQuestion
      let oldQuestionMap = {}
      if (Array.isArray(oldExamQuestion.questionsList)) {
        oldExamQuestion.questionsList.forEach(item => {
          oldQuestionMap[item.question_id] = item
        })
      }

      let { questionsList, parts } = data
      // 将老数据更新至新数据中
      // 更新修改题干内容
      if (Array.isArray(questionsList) && Array.isArray(parts)) {
        questionsList.forEach((item, index) => {
          let question = oldQuestionMap[item.question_id]
          if (question) {
            // 用户操作内容: 做题答案、状态，是否标记
            let { userAnswer, status, questionModel, marked } = question
            Object.assign(item, { userAnswer, status, questionModel, marked })
          }
        })
        parts.forEach(item => {
          let { questions, answerList } = item
          if (Array.isArray(questions)) {
            // 更新左侧menu
            questions.forEach((question, index) => {
              let _question = oldQuestionMap[item.question_id]
              if (_question) {
                let { userAnswer, status, questionModel, marked } = _question
                Object.assign(question, {
                  userAnswer,
                  status,
                  questionModel,
                  marked
                })
              }
            })
          }
          // 更新右侧答题卡
          answerList.forEach(answer => {
            let _question = oldQuestionMap[answer.question_id]
            if (_question) {
              let { index } = _question
              Object.assign(answer, { index })
            }
          })
        })
      }

      // 更新题目
      this.commit('exam/setExamQuestion', data)
    },
    // 更新做题答案
    updateAnswerCard(state, val) {
      let { questionsList = [] } = state.examQuestion
      let count = 0
      questionsList.forEach(item => {
        if (item.question_id === val.question_id) {
          let { status, userAnswer, marked, is_all_aq } = val
          item.status = status
          item.userAnswer = userAnswer
          item.marked = marked
          if (is_all_aq) {
            item.options = val.options
          }
        }
        if (item.status !== 'n') {
          ++count
        }
      })
      state.examDoneNum = count
      this.commit('exam/setExamQuestion', state.examQuestion)
    },
    updateExamDoneNum(state) {
      let { questionsList = [] } = state.examQuestion
      let count = 0
      questionsList.forEach(item => {
        if (item.status !== 'n') {
          ++count
        }
      })
      state.examDoneNum = count
    },
    CLEAR_ANSWER_CARD_DATA(state) {
      let { questionsList = [], parts } = state.examQuestion
      let count = 0
      questionsList.forEach(item => {
        item.status = 'n'
      })
      this.commit('exam/updateExamDoneNum')
      this.commit('exam/setExamQuestion', state.examQuestion)
    },
    //设置评论信息
    setAllComments(comments) {
      //comments因为指纹，可能远程没有最新的评论，就只会返回指纹，没有数据，所以只合并有数据的
      let commentsList = Object.entries(comments)
      //先快速检查一下，有没有需要拿缓存的
      let isNeedCombine = commentsList.some(
        ([key, value]) => !value.comments && !value.sticks
      )
      //如果匹配
      if (isNeedCombine) {
        //合并数据到缓存中
        let commentsCache = storage.get('examComments_' + this.examId)
        try {
          let commentsParse = JSON.parse(commentsCache)
          let newComments = {}

          commentsList.forEach(([key, value]) => {
            if (!value.comments && !value.sticks) {
              //从缓存取
              if (commentsParse[key]) newComments[key] = commentsParse[key]
            } else {
              //覆盖本地
              newComments[key] = value
            }
          })
          this.allComments = newComments
        } catch (e) {
          /*出错不更新*/
        }
      } else {
        //直接存缓存
        this.allComments = comments
      }
      storage.set(
        'examComments_' + this.examId,
        JSON.stringify(this.allComments)
      )
      let parseAllComments = {}
      Object.entries(this.allComments).forEach(([key, value]) => {
        let { comments: itemComments, sticks: itemSticks } = value
        let parse = findSticksInComments(itemSticks, itemComments)
        value.comments = parse.comments
        value.sticks = parse.sticks

        parseAllComments[key] = value
      })

      this.allComments = parseAllComments
    },

    //更多评论，分页
    setAllCommentsByMore({ comments = [], ukey }) {
      let current = this.allComments[ukey]
      //如果还没有该试题的评论信息，不过一般不会出现这种情况，兼容一下
      if (!current) {
        this.allComments[ukey] = {
          comment_total: comments.length,
          comments,
          sticks: [],
          total: comments.length
        }
        return
      }

      //存入更多评论
      this.allComments[ukey].comments.push(...comments)
      this.commit('setIsQuestMoreComments', false)
      // 如果没有请求到新的评论则表示没有了
      if (!comments.length) {
        this.commit('setIsQuestMoreComments', true)
      }
    },

    //设置回复信息
    setReplyInfo(replyInfo) {
      this.replyInfo = replyInfo
    },

    //设置所有回复信息列表
    setReplyAllInfo(replyList) {
      this.replyAllInfo = replyList
    },
    //设置点赞，取消点赞 1 - 点赞  4 - 取消点赞
    setReplyLike({ type, objectIds }) {
      //修改点赞集合数据
      objectIds.forEach(objectId => {
        let findIndex = this.allLikes.findIndex(item => item === objectId)
        /* eslint-disable */
        if (type === 1 && findIndex === -1) {
          //点赞操作且没点赞过
          this.allLikes.push(objectId)
        } else if (type === 4 && findIndex > -1) {
          //取消已点赞
          this.allLikes.splice(findIndex, 1)
        }
        /* eslint-enable */
      })

      storage.set(
        'examCommentsLikes_' + this.examId,
        JSON.stringify(this.allLikes)
      )
    },

    //设置当前操作的评论的点赞数
    setReplyLikeNumber({ type, item }) {
      if (type === 4) {
        if (item.thumbs > 0) item.thumbs--
      } else {
        item.thumbs++
      }
    },

    //更新本地评论缓存数据
    updateComments({ newData, params }) {
      let {
        comment_type: commentType,
        ukey,
        object_id,
        reply_object_id
      } = params
      let objectId = reply_object_id ? reply_object_id : object_id
      let commentsCache = storage.get('examComments_' + this.examId)
      let allComments = {}

      switch (commentType) {
        case 1: //1 - 点赞别人的讨论
        case 4: //4 - 取消点赞
          this.commit('setReplyLike', {
            type: commentType,
            objectIds: [objectId]
          })
          break
        case 3: //3 - 回复别人，有可能是精彩评论，有可能是最新评论里的，此时肯定有缓存
          {
            //修改数据只修改store缓存中的数据，不去修改storage中的，因为每次刷新会更新storage
            let { allComments: currentAllcomments } = this
            let commentsParse = Vue.prototype.cloneDeep(currentAllcomments)

            let current = commentsParse[ukey] || {}
            let { comments = [], sticks = [], total = 0 } = current

            //更新的时候注意，在精彩和最新都可能有这条评论，都要更新到
            let currentReplys = [
              comments.find(item => item.object_id === object_id),
              sticks.find(item => item.object_id === object_id)
            ]

            currentReplys.forEach(currentReply => {
              if (currentReply) {
                if (currentReply.replys) {
                  //回复顶层评论或者二级评论，都塞入二级评论
                  currentReply.replys.push(newData)
                  currentReply.reply_total++
                } else {
                  //回复顶层评论
                  currentReply.replys = [newData]
                  currentReply.reply_total = 1
                }
              }
            })

            current.total = !total ? 1 : total + 1
            allComments = commentsParse

            this.commit('setAllComments', allComments)
            //如果有this.replyAllInfo，表示正在评论的是查看全部里的评论，还需要push一条
            if (this.replyAllInfo) {
              let tmp = {}
              tmp.replys = this.replyAllInfo.replys.slice(0)
              tmp.replys.push(newData)
              tmp.reply_total = this.replyAllInfo.reply_total + 1
              this.commit(
                'setReplyAllInfo',
                Object.assign({}, this.replyAllInfo, tmp)
              )
            }
          }
          break

        case 2: //2 - 新增评论
          {
            let newComment = {
              ...newData,
              ...{
                replys: [],
                reply_total: 0
              }
            }
            //修改数据只修改store缓存中的数据，不去修改storage中的，因为每次刷新会更新storage
            let { allComments: currentAllcomments } = this
            if (currentAllcomments) {
              let commentsParse = Vue.prototype.cloneDeep(currentAllcomments)
              //判断下本地是否已经有评论信息了，如果有则追加
              if (Object.keys(commentsParse).length) {
                let current = commentsParse[ukey]
                if (!current) {
                  commentsParse[ukey] = {
                    comment_total: 1,
                    comments: [newComment],
                    fingerprint: '',
                    sticks: [],
                    total: 1
                  }
                } else {
                  let { comments = [] } = current
                  comments.unshift(newComment)
                  current.total++
                }

                allComments = commentsParse
              } else {
                //没有则新增
                allComments = {
                  [ukey]: {
                    comment_total: 1,
                    comments: [newComment],
                    fingerprint: '',
                    sticks: [],
                    total: 1
                  }
                }
              }
            } else {
              allComments = {
                [ukey]: {
                  comment_total: 1,
                  comments: [newComment],
                  fingerprint: '',
                  sticks: [],
                  total: 1
                }
              }
            }
            this.commit('setAllComments', allComments)
          }
          break
      }
    },
    //设置是否正在请求评论的flag
    setIsQuestMoreComments(flag) {
      this.isQuestMoreComments = flag
    },
    //设置精彩区讨论类型
    setCommentStick(type) {
      this.commentStick = type
    },
    //设置点赞/评论按钮禁用
    setDisabledReplyBtn(type) {
      this.isDisabledReplyBtn = type
    }
  },
  actions: {
    setExamInitModel({ commit }, val) {
      commit('SET_EXAM_INIT_MODEL', val)
    },
    setExamModel({ commit }, val) {
      if (![1, 2, 3].includes(val)) return
      commit('SET_EXAM_MODEL', val)
    },
    setExamId({ commit }, val) {
      commit('SET_EXAM_ID', val)
    },
    setCurrentQuestion({ commit }, val) {
      commit('SET_CURRENT_QUESTION', val)
    },
    setIsSubmitedPaper({ commit }, val) {
      commit('SET_IS_SUBMITED_PAPER', val)
    },
    setSubQuestionIndex({ commit }, val) {
      commit('SET_SUB_QUESTION_INDEX', val)
    },
    clearAnswerCardData({ commit }) {
      commit('CLEAR_ANSWER_CARD_DATA')
    },
    //请求试题的评论
    //ukey - 如果传入了ukey，则请求对应的评论，用于做完一道题后请求该题的评论
    //如果不传，则请求所有已做的题的评论，用于首次渲染
    requestComments(ukey) {
      this.commit('setCommentStick', 1)

      if (ukey && this.allComments[ukey])
        return Promise.resolve(this.allComments[ukey])

      //请求全部评论时，判断本地缓存中是否有数据，如果有，先存入vuex，加快渲染速度，同时请求接口更新
      let commentsCache = storage.get('examComments_' + this.examId)
      let commentsLikesCache = storage.get('examCommentsLikes_' + this.examId)
      if (!ukey && commentsCache) {
        try {
          let commentsParse = JSON.parse(commentsCache) || {}
          let commentsLikesParse = JSON.parse(commentsLikesCache) || []
          this.commit('setAllComments', commentsParse)
          this.commit('setReplyLike', {
            type: 1,
            objectIds: commentsLikesParse
          })
        } catch (e) {}
      }

      //缓存中没有数据，则直接去接口取
      let ukeys = setUkeys(this.answerCardData, commentsCache, ukey) || {}

      return getExamComments({
        exam_id: this.examId,
        subject_id: this.subjectId,
        exam_type: this.examType,
        ukeys
      })
        .then(res => {
          let { comments, likes } = res
          //设置缓存
          this.commit('setAllComments', comments)
          this.commit('setReplyLike', {
            type: 1,
            objectIds: Object.keys(likes)
          })
        })
        .catch(() => {})
    },
    //请求单个试题的评论
    requestSingleComments(params) {
      this.commit('setCommentStick', 2)
      return getSingleExamComments(params)
        .then(res => {
          let { likes, sticks, comments, total, comment_total } = res

          let parse = findSticksInComments(sticks, comments)

          let allComments = {
            likes,
            [params.ukey]: {
              sticks: parse.sticks,
              comments: parse.comments,
              total,
              comment_total
            }
          }

          //设置缓存
          this.commit('setAllComments', allComments)
          this.commit('setReplyLike', {
            type: 1,
            objectIds: Object.keys(likes)
          })
        })
        .catch(() => {})
    },
    //获取某试题更多评论
    requestMoreComments(ukey) {
      if (this.isQuestMoreComments) return
      this.commit('setIsQuestMoreComments', true)
      //查一下缓存中有没有这个评论，如果没有，则请求开始的10条
      //如果有，则请求后续的10条
      let currentQuestionCommentCache = this.allComments[ukey]
      let start = 0
      let end = 0
      //如果有缓存
      if (currentQuestionCommentCache) {
        let { total = 0, comments } = currentQuestionCommentCache
        comments = comments || []
        let len = comments.length
        //如果已经没有更多了，则不加载
        if (len >= total) return this.commit('setIsQuestMoreComments', false)

        //加载更多
        start = len
        end = start + 10
      } else {
        end = 10
      }

      let params = {
        exam_id: this.examId,
        subject_id: this.subjectId,
        start,
        end,
        exam_type: this.examType,
        comment_type: 2,
        ukey
      }
      return getMoreExamComments(params)
        .then(res => {
          let { comments, likes } = res
          //设置缓存
          this.commit('setAllCommentsByMore', { comments, ukey })
          this.commit('setReplyLike', {
            type: 1,
            objectIds: likes
          })
        })
        .catch(() => this.commit('setIsQuestMoreComments', false))
    },
    //设置回复点赞，或取消点赞
    setReplyLike(item) {
      let objectId = item.reply_object_id
        ? item.reply_object_id
        : item.object_id
      //设置点赞，取消点赞 1 - 点赞  4 - 取消点赞
      let type = this.allLikes.includes(objectId) ? 4 : 1
      let params = {
        exam_id: this.examId,
        exam_type: this.examType,
        ukey: item.indexId,
        subject_id: this.subjectId,
        comment_type: type,
        object_id: objectId
      }
      this.commit('setDisabledReplyBtn', true)
      return saveExamComment(params)
        .then(
          () => {
            this.commit('setDisabledReplyBtn', false)
            this.commit('setReplyLike', { type, objectIds: [objectId] })
            this.commit('setReplyLikeNumber', { type, item: item.preItem })
          },
          rej => {
            this.commit('setDisabledReplyBtn', false)
            if (rej.errcode === 1112) {
              this.$toast(rej.errmsg)
            }
          }
        )
        .catch(() => {})
    }
  },
  getters: {
    // 是否从考试切换过模式
    isChangeExamModel({ examInitModel, isSubmitedPaper }) {
      if (typeof window === 'undefined') {
        return false
      }

      return (
        +examInitModel === 1 &&
        +getQuery(location.search).paper_type === 2 &&
        !isSubmitedPaper
      )
    },
    // 倒计时 页面显示的 hh:mm:ss
    examTimerText({ timeConsuming, examQuestion }) {
      if (isObject(examQuestion)) {
        let { duration } = examQuestion
        duration = duration * 60 - timeConsuming
        let hour = Math.floor(duration / 3600)
        let minute = Math.floor((duration % 3600) / 60)
        let second = duration % 60
        return `${hour < 10 ? '0' + hour : hour}:${
          minute < 10 ? '0' + minute : minute
        }:${second < 10 ? '0' + second : second}`
      }
    },
    // 用时 页面显示的 hh:mm:ss
    timeConsumingText({ timeConsuming }) {
      let hour = Math.floor(timeConsuming / 3600)
      let minute = Math.floor((timeConsuming % 3600) / 60)
      let second = timeConsuming % 60
      return `${hour < 10 ? '0' + hour : hour}:${
        minute < 10 ? '0' + minute : minute
      }:${second < 10 ? '0' + second : second}`
    },
    // 已做题数
    examDoneNumber({ examQuestion: { questionsList = [] } }) {
      let count = 0
      questionsList.forEach(item => {
        if (item.status !== 'n') {
          ++count
        }
      })
      return count
    }
  }
}

// 获取参数
function getQuery(query) {
  if (typeof window === 'undefined') return {}
  var ret = {}
  var searchReg = /([^&=?]+)=([^&]+)/g
  var name, value
  let match = searchReg.exec(query)
  while (match) {
    name = match[1]
    value = match[2]
    ret[name] = decodeURIComponent(value)
    match = searchReg.exec(query)
  }
  return ret
}
function isObject(o) {
  return Object.prototype.toString.call(o) === '[object Object]'
}

function setUkeys(data, cache, ukey) {
  let ukeys = {}
  if (ukey) {
    ukeys = {
      [ukey]: ''
    }
  } else {
    //收集所有的ukeys
    data.forEach(item => {
      item.answerList.forEach(citem => (ukeys[citem.indexId] = ''))
    })

    //获取本地的评论，添加指纹
    if (cache) {
      try {
        let commentsParse = JSON.parse(cache) || {}
        Object.entries(commentsParse).forEach(([key, value]) => {
          if (ukeys.hasOwnProperty(key)) ukeys[key] = value.fingerprint
        })
      } catch (e) {}
    }
  }

  return ukeys
}

//这个操作是为了找出comments中与sticks中同一条评论，那么可以直接使用comments中的这一条
function findSticksInComments(sticks, comments) {
  //因为是引用类型
  sticks.forEach((item, index) => {
    let find = comments.find(citem => citem.object_id === item.object_id)
    if (find) sticks.splice(index, 1, find)
  })

  return { sticks, comments }
}
